#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""代码自动补全组件"""

import re
import logging
from PyQt5.QtWidgets import (QCompleter, QListView, QStyledItemDelegate,
                             QAbstractItemView, QApplication)
from PyQt5.QtCore import Qt, QModelIndex, QSortFilterProxyModel, QStringListModel
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QFont, QColor


class CodeCompletion(QCompleter):
    """代码自动补全组件"""
    
    def __init__(self, parent=None):
        """初始化代码自动补全组件
        
        Args:
            parent: 父控件
        """
        super().__init__(parent)
        
        # 日志配置
        self.logger = logging.getLogger("CodeCompletion")
        
        # 自动补全数据
        self._completion_items = {
            "python": {
                # 基本类型和内置函数
                "types": ["int", "float", "str", "bool", "list", "tuple", 
                          "dict", "set", "None", "True", "False"],
                "builtins": ["print", "len", "range", "input", "type", 
                              "isinstance", "abs", "max", "min", "sum", 
                              "sorted", "reversed", "enumerate", "zip", 
                              "map", "filter", "open", "dir", "help"],
                "keywords": ["def", "class", "if", "elif", "else", "for", 
                              "while", "try", "except", "finally", "with", 
                              "import", "from", "as", "return", "yield", 
                              "break", "continue", "pass", "del", "global", 
                              "nonlocal", "assert", "raise"]
            },
            "pyqt5": {
                # PyQt5常用类和函数
                "widgets": ["QApplication", "QWidget", "QMainWindow", "QDialog",
                             "QPushButton", "QLabel", "QLineEdit", "QTextEdit",
                             "QComboBox", "QCheckBox", "QRadioButton", "QSpinBox",
                             "QSlider", "QListWidget", "QTreeWidget", "QTableWidget",
                             "QFileDialog", "QMessageBox", "QMenu", "QToolBar",
                             "QStatusBar", "QDockWidget"],
                "core": ["Qt", "QObject", "QTimer", "QThread", "QEvent",
                          "QSize", "QPoint", "QRect", "QColor", "QFont",
                          "QString", "QVariant", "QModelIndex"],
                "gui": ["QPainter", "QPixmap", "QImage", "QPen", "QBrush",
                         "QFont", "QPalette", "QClipboard"],
                "signals_slots": ["clicked", "pressed", "released", "toggled",
                                   "textChanged", "currentIndexChanged", "valueChanged",
                                   "activated", "triggered", "customContextMenuRequested"]
            }
        }
        
        # 构建模型
        self._model = QStandardItemModel()
        self.setModel(self._model)
        
        # 设置视图
        self._view = QListView()
        self.setPopup(self._view)
        
        # 配置自动补全
        self._configure_completer()
        
        # 初始化数据
        self._initialize_data()
    
    def _configure_completer(self):
        """配置自动补全组件"""
        # 设置补全模式
        self.setCompletionMode(QCompleter.PopupCompletion)
        
        # 设置大小写敏感度
        self.setCaseSensitivity(Qt.CaseInsensitive)
        
        # 设置过滤模式
        self.setFilterMode(Qt.MatchContains)
        
        # 设置模型排序
        self.setModelSorting(QCompleter.CaseInsensitivelySortedModel)
        
        # 配置视图
        self._view.setAlternatingRowColors(True)
        self._view.setUniformItemSizes(True)
        self._view.setSelectionMode(QAbstractItemView.SingleSelection)
        self._view.setItemDelegate(CompletionDelegate())
        
        # 设置最大显示项数
        self._view.setMaxVisibleItems(10)
    
    def _initialize_data(self):
        """初始化自动补全数据"""
        # 添加Python基本数据
        self._add_category("Python关键字", self._completion_items["python"]["keywords"], 
                          QColor(255, 165, 0))  # 橙色
        self._add_category("Python内置函数", self._completion_items["python"]["builtins"], 
                          QColor(0, 128, 0))  # 绿色
        self._add_category("Python基本类型", self._completion_items["python"]["types"], 
                          QColor(128, 0, 128))  # 紫色
        
        # 添加PyQt5数据
        self._add_category("PyQt5窗口部件", self._completion_items["pyqt5"]["widgets"], 
                          QColor(0, 0, 255))  # 蓝色
        self._add_category("PyQt5核心类", self._completion_items["pyqt5"]["core"], 
                          QColor(0, 128, 128))  # 青色
        self._add_category("PyQt5图形类", self._completion_items["pyqt5"]["gui"], 
                          QColor(255, 0, 0))  # 红色
        self._add_category("PyQt5信号/槽", self._completion_items["pyqt5"]["signals_slots"], 
                          QColor(128, 128, 0))  # 橄榄色
    
    def _add_category(self, category_name, items, color=None):
        """添加一个类别的自动补全项
        
        Args:
            category_name: 类别名称
            items: 项目列表
            color: 项目颜色
        """
        # 创建类别项
        category_item = QStandardItem(category_name)
        category_item.setSelectable(False)
        
        # 设置类别项字体
        font = QFont()
        font.setBold(True)
        font.setItalic(True)
        category_item.setFont(font)
        
        # 添加类别项到模型
        self._model.appendRow(category_item)
        
        # 添加项目到类别
        for item_name in items:
            item = QStandardItem(item_name)
            
            # 设置项目数据
            item.setData(category_name, Qt.UserRole + 1)
            
            # 设置项目颜色
            if color:
                item.setData(color, Qt.UserRole + 2)
                
            # 添加项目到模型
            category_item.appendRow(item)
    
    def add_custom_completion_items(self, category_name, items, color=None):
        """添加自定义的自动补全项
        
        Args:
            category_name: 类别名称
            items: 项目列表
            color: 项目颜色
        """
        # 检查是否已存在该类别
        existing_category = None
        for i in range(self._model.rowCount()):
            if self._model.item(i).text() == category_name:
                existing_category = self._model.item(i)
                break
        
        # 如果类别不存在，创建新类别
        if not existing_category:
            existing_category = QStandardItem(category_name)
            existing_category.setSelectable(False)
            
            # 设置类别项字体
            font = QFont()
            font.setBold(True)
            font.setItalic(True)
            existing_category.setFont(font)
            
            # 添加类别项到模型
            self._model.appendRow(existing_category)
        
        # 添加项目到类别
        for item_name in items:
            # 检查项目是否已存在
            exists = False
            for j in range(existing_category.rowCount()):
                if existing_category.child(j).text() == item_name:
                    exists = True
                    break
            
            if not exists:
                item = QStandardItem(item_name)
                
                # 设置项目数据
                item.setData(category_name, Qt.UserRole + 1)
                
                # 设置项目颜色
                if color:
                    item.setData(color, Qt.UserRole + 2)
                    
                # 添加项目到模型
                existing_category.appendRow(item)
    
    def remove_custom_completion_items(self, category_name, items=None):
        """移除自定义的自动补全项
        
        Args:
            category_name: 类别名称
            items: 项目列表，如果为None则移除整个类别
        """
        # 查找类别
        category_index = -1
        for i in range(self._model.rowCount()):
            if self._model.item(i).text() == category_name:
                category_index = i
                break
        
        if category_index == -1:
            self.logger.warning(f"类别不存在: {category_name}")
            return
        
        category_item = self._model.item(category_index)
        
        # 如果没有指定项目，移除整个类别
        if items is None:
            self._model.removeRow(category_index)
            return
        
        # 移除指定项目
        for item_name in items:
            for j in range(category_item.rowCount()):
                if category_item.child(j).text() == item_name:
                    category_item.removeRow(j)
                    break
    
    def clear_custom_completion_items(self):
        """清除所有自定义的自动补全项"""
        # 保留预设的类别
        preset_categories = ["Python关键字", "Python内置函数", "Python基本类型",
                             "PyQt5窗口部件", "PyQt5核心类", "PyQt5图形类", "PyQt5信号/槽"]
        
        # 移除非预设的类别
        rows_to_remove = []
        for i in range(self._model.rowCount()):
            if self._model.item(i).text() not in preset_categories:
                rows_to_remove.append(i)
        
        # 从后往前移除，避免索引变化
        for i in reversed(rows_to_remove):
            self._model.removeRow(i)
    
    def update_completion_items(self, text, cursor_position):
        """更新自动补全项
        
        Args:
            text: 编辑器中的文本
            cursor_position: 光标位置
            
        Returns:
            bool: 是否应该显示自动补全
        """
        try:
            # 获取光标前的文本
            prefix = text[:cursor_position]
            
            # 使用正则表达式提取当前正在输入的单词
            match = re.search(r'[a-zA-Z0-9_]+$', prefix)
            if not match:
                return False
            
            current_word = match.group()
            
            # 设置完成前缀
            self.setCompletionPrefix(current_word)
            
            # 如果有匹配项，显示自动补全
            if self.completionCount() > 0:
                self.complete()
                return True
            
            return False
        except Exception as e:
            self.logger.error(f"更新自动补全项失败: {str(e)}")
            return False
    
    def set_completion_case_sensitivity(self, case_sensitive):
        """设置自动补全的大小写敏感度
        
        Args:
            case_sensitive: 是否大小写敏感
        """
        if case_sensitive:
            self.setCaseSensitivity(Qt.CaseSensitive)
        else:
            self.setCaseSensitivity(Qt.CaseInsensitive)
    
    def set_completion_filter_mode(self, filter_mode):
        """设置自动补全的过滤模式
        
        Args:
            filter_mode: 过滤模式，可以是 'startswith', 'contains', 'exact'
        """
        if filter_mode == 'startswith':
            self.setFilterMode(Qt.MatchStartsWith)
        elif filter_mode == 'contains':
            self.setFilterMode(Qt.MatchContains)
        elif filter_mode == 'exact':
            self.setFilterMode(Qt.MatchExactly)
        else:
            self.logger.warning(f"未知的过滤模式: {filter_mode}")
    
    def set_max_visible_items(self, max_items):
        """设置最大可见项数
        
        Args:
            max_items: 最大可见项数
        """
        self._view.setMaxVisibleItems(max_items)


class CompletionDelegate(QStyledItemDelegate):
    """自动补全项的委托类"""
    
    def __init__(self, parent=None):
        """初始化自动补全项的委托类
        
        Args:
            parent: 父控件
        """
        super().__init__(parent)
    
    def initStyleOption(self, option, index):
        """初始化样式选项
        
        Args:
            option: 样式选项
            index: 项目索引
        """
        super().initStyleOption(option, index)
        
        # 检查是否是类别项
        if not index.parent().isValid():
            # 类别项的样式
            option.backgroundBrush.setColor(QColor(240, 240, 240))
            option.font.setBold(True)
            option.font.setItalic(True)
        else:
            # 项目项的样式
            # 获取颜色数据
            color = index.data(Qt.UserRole + 2)
            if color is not None and isinstance(color, QColor):
                option.palette.setColor(option.palette.Text, color)
            
            # 获取类别数据
            category = index.data(Qt.UserRole + 1)
            if category:
                # 设置工具提示
                option.toolTip = f"{index.data()}\n类别: {category}"
    
    def sizeHint(self, option, index):
        """设置项目大小
        
        Args:
            option: 样式选项
            index: 项目索引
            
        Returns:
            QSize: 项目大小
        """
        size = super().sizeHint(option, index)
        
        # 增加垂直间距
        size.setHeight(size.height() + 4)
        
        return size


class CodeSnippetManager:
    """代码片段管理器"""
    
    def __init__(self):
        """初始化代码片段管理器"""
        # 日志配置
        self.logger = logging.getLogger("CodeSnippetManager")
        
        # 代码片段
        self._snippets = {
            "python": {
                "if": "if {condition}:\n    {content}",
                "if_else": "if {condition}:\n    {content}\nelse:\n    {else_content}",
                "for": "for {item} in {iterable}:\n    {content}",
                "while": "while {condition}:\n    {content}",
                "def": "def {name}({params}):\n    """{docstring}"""\n    {content}\n    return {return_value}",
                "class": "class {name}({parent}):\n    """{docstring}"""\n\n    def __init__(self, {params}):\n        {init_content}",
                "try_except": "try:\n    {try_content}\nexcept {exception} as {var}:\n    {except_content}",
                "with": "with {context_manager} as {var}:\n    {content}",
                "import": "import {module}",
                "from_import": "from {module} import {name}",
                "list_comp": "[{expr} for {item} in {iterable} if {condition}]",
                "dict_comp": "{{{key}: {value} for {item} in {iterable} if {condition}}}"
            },
            "pyqt5": {
                "qapplication": "import sys\nfrom PyQt5.QtWidgets import QApplication, {widgets}\n\nif __name__ == '__main__':\n    app = QApplication(sys.argv)\n    {app_content}\n    sys.exit(app.exec_())",
                "mainwindow": "from PyQt5.QtWidgets import QMainWindow, QWidget, QVBoxLayout\n\nclass {name}(QMainWindow):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n        \n        # 设置窗口标题和大小\n        self.setWindowTitle('{title}')\n        self.resize({width}, {height})\n        \n        # 创建中央部件\n        self.central_widget = QWidget()\n        self.setCentralWidget(self.central_widget)\n        \n        # 创建布局\n        self.layout = QVBoxLayout(self.central_widget)\n        \n        # 添加部件\n        {widgets_content}",
                "signal_slot": "{sender}.{signal}.connect({receiver})",
                "qpushbutton": "from PyQt5.QtWidgets import QPushButton\n\n{name} = QPushButton('{text}', self)\n{name}.clicked.connect({slot})\n{name}.setGeometry({x}, {y}, {width}, {height})",
                "qlabel": "from PyQt5.QtWidgets import QLabel\n\n{name} = QLabel('{text}', self)\n{name}.setGeometry({x}, {y}, {width}, {height})"
            }
        }
    
    def get_snippet(self, language, name):
        """获取代码片段
        
        Args:
            language: 语言
            name: 片段名称
            
        Returns:
            str: 代码片段
        """
        if language in self._snippets and name in self._snippets[language]:
            return self._snippets[language][name]
        
        self.logger.warning(f"代码片段不存在: {language}.{name}")
        return None
    
    def add_snippet(self, language, name, content):
        """添加代码片段
        
        Args:
            language: 语言
            name: 片段名称
            content: 片段内容
        """
        if language not in self._snippets:
            self._snippets[language] = {}
        
        self._snippets[language][name] = content
        self.logger.info(f"添加代码片段: {language}.{name}")
    
    def remove_snippet(self, language, name):
        """移除代码片段
        
        Args:
            language: 语言
            name: 片段名称
            
        Returns:
            bool: 是否移除成功
        """
        if language in self._snippets and name in self._snippets[language]:
            del self._snippets[language][name]
            self.logger.info(f"移除代码片段: {language}.{name}")
            return True
        
        self.logger.warning(f"代码片段不存在: {language}.{name}")
        return False
    
    def get_all_snippets(self, language=None):
        """获取所有代码片段
        
        Args:
            language: 语言，如果为None则获取所有语言的片段
            
        Returns:
            dict: 代码片段字典
        """
        if language:
            return self._snippets.get(language, {}).copy()
        
        return {lang: snippets.copy() for lang, snippets in self._snippets.items()}
    
    def expand_snippet(self, language, name, **kwargs):
        """展开代码片段，替换占位符
        
        Args:
            language: 语言
            name: 片段名称
            **kwargs: 占位符的值
            
        Returns:
            str: 展开后的代码片段
        """
        snippet = self.get_snippet(language, name)
        if not snippet:
            return None
        
        try:
            # 替换占位符
            expanded = snippet.format(**kwargs)
            return expanded
        except KeyError as e:
            self.logger.error(f"展开代码片段失败: 缺少参数 {str(e)}")
            return None
        except Exception as e:
            self.logger.error(f"展开代码片段失败: {str(e)}")
            return None
    
    def search_snippets(self, query, language=None):
        """搜索代码片段
        
        Args:
            query: 搜索查询
            language: 语言，如果为None则搜索所有语言的片段
            
        Returns:
            list: 匹配的代码片段列表 [(language, name, snippet), ...]
        """
        results = []
        
        # 确定要搜索的语言
        languages = [language] if language else self._snippets.keys()
        
        # 搜索代码片段
        for lang in languages:
            if lang not in self._snippets:
                continue
            
            for name, snippet in self._snippets[lang].items():
                # 搜索名称和内容
                if query.lower() in name.lower() or query.lower() in snippet.lower():
                    results.append((lang, name, snippet))
        
        return results